Objective: Learn the basics of `ggplot2()’ by visualizing a sample data set

Learning Outcomes: Understand the purpose and effective use of the following tools –line chart, histogram, box plot, scatter plot, bubble chart, and bullet graph.

Clear the workspace

Let’s start with cleaning the workspace and loading the required packages. Today, we will use a new package, ggplot2(), which is a powerful R graphic package. I highly recommend this site (and book) for more examples: http://www.cookbook-r.com/Graphs/

rm(list = ls())
library(readxl)
library(tidyverse)
library(ggplot2)

Understanding the dataset

In this exercise, we will use the crime statistics in large U.S. cities for 2009-2014. This dataset is obtained from the Uniform Crime Reports (UCR) published by the FBI (https://ucr.fbi.gov/crime-in-the-u.s/2014/crime-in-the-u.s.-2014). This file includes the number of crime occurrences per population (crime rates) and the number of police officers killed or assaulted in the line of duty.

  1. Download Crimes 2009-2014.xlsx from Canvas Modules > Week 2.
  2. Open the file in Excel, and browse the data.
  3. Take a look at Data Dictionary tab, and understand what each crime data attribute is for.
crimes <- read_excel("Crimes 2009-2014.xlsx")

crimes
glimpse(crimes)
Rows: 1,546
Columns: 10
$ City                               <chr> "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Ancho…
$ State                              <chr> "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AL", "AL", "A…
$ Region                             <chr> "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", …
$ Year                               <chr> "12-31-1999", "12-31-2000", "12-31-2001", "12-31-2002", "12-31-2003", "12-31-2004", "12-31-2005", "12-31-2006"…
$ Population                         <dbl> 257762, 260283, 263588, 267280, 271085, 273714, 276109, 277692, 284142, 280068, 283300, 291826, 296955, 299143…
$ `Murder Rate`                      <dbl> 8.147050, 5.378761, 4.173179, 7.108650, 7.008872, 5.845518, 6.519165, 7.202224, 7.742608, 4.284674, 5.294741, …
$ `Violent Crime Rate`               <dbl> 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, …
$ `Violent Crime Rate in Prior Year` <dbl> NA, 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.37…
$ `Property Crime Rate`              <dbl> 4370.311, 4357.565, 4349.970, 4470.593, 4318.203, 3617.279, 4116.128, 4220.863, 3908.961, 3288.844, 3641.370, …
$ `Officer Assault Rate`             <dbl> 30.648428, 24.588621, 32.626675, 31.801856, 30.986591, 39.457244, 41.650218, 39.972343, 58.773430, 61.056601, …

Data Preparation

The names of variables contain spaces, which make it difficult to manage in R. Let’s rename variables.

# Change the variable names
colnames(crimes)<-c("city","state","region","date","population","murder_rate","violent_crime_rate","violent_crime_rate_pr","property_crime_rate","officer_assault_rate")
glimpse(crimes)
Rows: 1,546
Columns: 10
$ city                  <chr> "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Ancho…
$ state                 <chr> "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AL", "AL", "AL", "AL", "AL…
$ region                <chr> "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "P…
$ date                  <chr> "12-31-1999", "12-31-2000", "12-31-2001", "12-31-2002", "12-31-2003", "12-31-2004", "12-31-2005", "12-31-2006", "12-31-2007…
$ population            <dbl> 257762, 260283, 263588, 267280, 271085, 273714, 276109, 277692, 284142, 280068, 283300, 291826, 296955, 299143, 299455, 301…
$ murder_rate           <dbl> 8.147050, 5.378761, 4.173179, 7.108650, 7.008872, 5.845518, 6.519165, 7.202224, 7.742608, 4.284674, 5.294741, 4.797379, 4.3…
$ violent_crime_rate    <dbl> 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098, 22…
$ violent_crime_rate_pr <dbl> NA, 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098…
$ property_crime_rate   <dbl> 4370.311, 4357.565, 4349.970, 4470.593, 4318.203, 3617.279, 4116.128, 4220.863, 3908.961, 3288.844, 3641.370, 3500.031, 318…
$ officer_assault_rate  <dbl> 30.648428, 24.588621, 32.626675, 31.801856, 30.986591, 39.457244, 41.650218, 39.972343, 58.773430, 61.056601, 61.418990, 76…

Also, change the variable type of date as a date variable and create year for further analysis.

# create year variable
crimes$date<-as.Date(crimes$date,"%m-%d-%Y")
crimes
crimes$year<-format(crimes$date,"%Y")
glimpse(crimes)
Rows: 1,546
Columns: 11
$ city                  <chr> "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Ancho…
$ state                 <chr> "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AL", "AL", "AL", "AL", "AL…
$ region                <chr> "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "P…
$ date                  <date> 1999-12-31, 2000-12-31, 2001-12-31, 2002-12-31, 2003-12-31, 2004-12-31, 2005-12-31, 2006-12-31, 2007-12-31, 2008-12-31, 20…
$ population            <dbl> 257762, 260283, 263588, 267280, 271085, 273714, 276109, 277692, 284142, 280068, 283300, 291826, 296955, 299143, 299455, 301…
$ murder_rate           <dbl> 8.147050, 5.378761, 4.173179, 7.108650, 7.008872, 5.845518, 6.519165, 7.202224, 7.742608, 4.284674, 5.294741, 4.797379, 4.3…
$ violent_crime_rate    <dbl> 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098, 22…
$ violent_crime_rate_pr <dbl> NA, 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098…
$ property_crime_rate   <dbl> 4370.311, 4357.565, 4349.970, 4470.593, 4318.203, 3617.279, 4116.128, 4220.863, 3908.961, 3288.844, 3641.370, 3500.031, 318…
$ officer_assault_rate  <dbl> 30.648428, 24.588621, 32.626675, 31.801856, 30.986591, 39.457244, 41.650218, 39.972343, 58.773430, 61.056601, 61.418990, 76…
$ year                  <chr> "1999", "2000", "2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", "20…

Scatter plot

Let’s start by examining the relationship between the violent crime rate and the property crime rate in the major cities. You can visualize the relationship of two numeric variables by plotting a scatter plot where x- and y-axis represents each numeric variable.

Base R plot function

Using base R plot function:

plot(crimes$violent_crime_rate, crimes$property_crime_rate)

However, the combination of tidyverse and ggplot2 can help you create a nicer-looking chart in a more intrinsic way with more flexibility.

ggplot: Intro

ggplot() takes a dataset as the first argument, and you specify aesthetics (e.g. axes, color, type, etc) with the parameters in aes().

In ggplot(), you specify the dataset and aesthetics, and `geom_point() indicates you’d like to create a scatter plot.

ggplot(crimes, aes(x=violent_crime_rate,y=property_crime_rate))+
  geom_point()

We can create the same plot with a pipe operator:

crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
  geom_point()

Change colors, data point sizes, etc

If you want to apply the different color, shape, etc, for all points, you can do it by changing the parameter in `geom_point()’.

crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(size=5)


crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(size=5, alpha=0.2) #alpha for transparency: for densely populated data points


crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(col="blue")


crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(shape=4)


crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(col=2,shape=2,size =3)


crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
  geom_point(col="#86229A",shape=2,size =3)+
  labs(title="Violent vs. Property Crime Rate", x="Violent Crime Rate", y="Property Crime Rate")

Different colors, sizes, etc. by groups

If you want to use different colors by different groups, you can do it easily by setting it in aes()! You can change the aesthetics to deliver more information on a chart.

crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate, size=officer_assault_rate))+geom_point()


crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate, col=region))+geom_point()

You can do it in combination!

crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate,size=officer_assault_rate,col=region))+
  geom_point(shape=1)

Note that Officer Assault Rate is the number of police officers killed or assaulted in the line of duty. This bubble chart now shows that police officers are in more danger (as shown in bigger circles) in cities with higher crime rates.

Facet

You can also easily create separate charts by subgroups (i.e. regions in this case) using facet_wrap(), which creates charts, which share the same axes, and displays them in a panel.

crimes%>%
  ggplot(aes(y=property_crime_rate,x=violent_crime_rate,size=officer_assault_rate,colour=region))+
  geom_point(shape=1)+
  facet_wrap(~region)

Add a statistics layer

We can also add some statistical analysis results to the charts.

LOESS, which is a default smoothing method of geom_smooth(), is a non-parametric form of regression that uses a weighted, sliding-window, average to calculate a line of best fit.

crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
  geom_point(shape=1)+
  geom_smooth(method=loess)

A linear regression model can be added into a scatter plot by adding specifying the smoothing method as “lm”.

crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
  geom_point(shape=1)+
  geom_smooth(method=lm)

Using facet_wrap(), you can compare the trend by different regions in the United States.fullrange=TRUE extends the span of the linear model to the full range.

crimes%>%
  ggplot(aes(x=violent_crime_rate,y=property_crime_rate, col=region))+
  geom_point(shape=1)+
  geom_smooth(method=lm,fullrange=TRUE)+
  facet_wrap(~region)

Bar charts

A bar chart is a simple way to depict the frequencies of the values of a categorical attribute.

How many cities are contained in this dataset by region? In fact, the dataset is a panel dataset (i.e. repeated observations over time for the same entities) at a city-year level, where each city appears once per year. So, we can count the number of cities, if we set year to a specific year (e.g. year=2000), and count the number of observations.

Let’s filter data with year==2000 and then call ggplot() with geom_bar() to create a bar chart.

crimes%>%
  filter(year==2000)%>%
  ggplot(aes(x=region))+
  geom_bar()

Histogram

A histogram shows the frequency distribution for a numerical attribute.

The range of a numerical attribute is discretized into a fixed number of intervals (“bins”), usually of equal length. For each interval, the (absolute) frequency of values falling into each interval is indicated by the height of a bar.

Let’s examine the distribution of the property crime rate.

crimes%>%
  ggplot(aes(x=property_crime_rate))+
  geom_histogram()

Change bin width, fill, color..

Try changing the value of binwidth. You will see the shape of the histogram changes. Also, as we did with a scatterplot, you can change the color of the histogram.

crimes%>%
  ggplot(aes(x=property_crime_rate))+
  geom_histogram(binwidth=1000, col="black",fill="red")

Overlapping histograms

We can easily create histograms for different regions using facet_wrap().

crimes%>%
  ggplot(aes(x=property_crime_rate, fill=region))+
  geom_histogram(binwidth=100)+
  facet_wrap(~region)

But you can also display these histograms in one chart with various options.

crimes%>%
  ggplot(aes(x=property_crime_rate,fill=region))+
  geom_histogram(binwidth=100)


crimes%>%
  ggplot(aes(x=property_crime_rate,fill=region))+
  geom_histogram(binwidth=100,alpha=0.3, position="identity")


crimes%>%
  ggplot(aes(x=property_crime_rate,fill=region))+
  geom_histogram(binwidth=100,position="stack")


crimes%>%
  ggplot(aes(x=property_crime_rate,fill=region))+
  geom_histogram(binwidth=1000,position="dodge")

Instead of a histogram, you can create a density function in a similar manner.

crimes%>%
  ggplot(aes(x=property_crime_rate, fill=region))+
  geom_density(alpha=0.5)

Box plot

A boxplot is a very compact way to visualize and summarize the key statistics of a numeric attribute.

Let’s examine the distribution of the property crime rate (which will be displayed in y-axis) by cities (which will be x-axis). Because we have too many cities in our datasets, let’s focus on the cities in Florida.

crimes%>%
  filter(state=="FL")%>%
  ggplot(aes(x=city,y=property_crime_rate,fill=city))+
  geom_boxplot()

The upper whisker extends from the hinge to the largest value no further than 1.5 * IQR from the hinge (where IQR is the inter-quartile range, or distance between the first and third quartiles). The lower whisker extends from the hinge to the smallest value at most 1.5 * IQR of the hinge. Data beyond the end of the whiskers are called “outlying” points and are plotted individually.

Time Series with Line Graph

Let’s examine the trend of the violent crime rate of the cities in New York state. Let’s first examine the data.

crimes%>%
  filter(state=="NY")%>%
  distinct(city)

crimes%>%
  filter(state=="NY")

For line graphs, the data points must be grouped so that it knows which points to connect. If you want to connect all points, set group=1. Because we want to connect the points by cities, we will set group=city.

crimes%>%
  filter(state=="NY")%>%
   ggplot(aes(x=year,y=violent_crime_rate,group=city))+geom_line()

But we lost the information about which line is for which city. Let’s use different types or colors of lines, so that we can distinguish them.

crimes%>%
  filter(state=="NY")%>%
   ggplot(aes(x=year,y=violent_crime_rate, group=city,col=city))+geom_line()


crimes%>%
  filter(state=="NY")%>%
   ggplot(aes(x=year,y=violent_crime_rate, group=city,linetype=city))+geom_line()

Assignment 2

By modifying the code below, create box plots that show the range of the violent crime rate for each state in the South region, where each box represents a state. FYI, six states are categorized as South in the dataset. After creating the chart, answer the following questions.

crimes %>%
  filter(region == "South") %>%
  ggplot(aes(x = state, y = violent_crime_rate, fill=state)) +
  geom_boxplot()

Q1. Which state has the city that has the lowest violent crime rate in the South region?

KY: Kentucky

Q2. Which state has the highest median value of the violent crime rate?

Tennessee (TN)

Q3. By modifying the code below, create scatterplots that show the relationship between the officer assault rate (x-axis) and the murder rate (y-axis) by the states in the Northeast region. It will produce four scatter plots with regression lines, one for each state.

Which state shows the strongest negative correlation (i.e. the steeper, downward slope of regression lines)?

NJ : New Jersey

crimes %>%
  filter(region == "Northeast") %>%
  ggplot(aes(x = officer_assault_rate, y = murder_rate)) +
  geom_point(shape = 1) +
  geom_smooth(method = lm, fullrange = TRUE) +
  facet_wrap(~ state)

Q4.By modifying the code below, create a histogram that shows the distribution of property crime rate in year 2002. Set the binwidth=2000. Which of the bins contains the largest number of cities?

crimes %>%
  filter(year == "2002") %>%
  ggplot(aes(x = property_crime_rate)) +
  geom_histogram(binwidth = 2000, colour = "black", fill = "white")

  1. The bin whose x-axis values go from 0 to 2500.
  2. The bin whose x-axis values go from 2500 to 5000.
  3. The bin whose x-axis values go from 5000 to 7500.
  4. The bin whose x-axis values go from 7500 to 10000.
  5. The bin whose x-axis values go from 10000. to 12500

Answer: The bin whose x-axis values go from 5000 to 7500. This bin contains more than 40 cities, making it the one with the largest number of cities in 2002.

Q5. Similar to Assignment 1, generate a report from “Creating-Charts-Student.Rmd”. This time, please knit it in a Word document. Change the author name on the top of this R markdown file to your name. Compile this R markdown file into a Word document and submit it through the course Canvas. Your report should contain all the codes and the results of in-class exercises as well as the codes for the assignment questions.

Q6. Create a dashboard with Tableau by following the instruction in “Creating-Charts-Tableau.doc”. After creating a dashboard, export your Tableau dashboard view as PowerPoint. Click “File>Export As Powerpoint”, and include “This View”. It will create a PPT file that includes a snapshot of the dashboard. Submit this ppt file through Canvas as your answer for Question 6.

LS0tCnRpdGxlOiAiRXhwbG9yYXRvcnkgQW5hbHlzaXMgd2l0aCBWaXN1YWxpemF0aW9uIgphdXRob3I6ICJQaXl1c2ggQWdyYXdhbCIKb3V0cHV0OgogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCk9iamVjdGl2ZTogTGVhcm4gdGhlIGJhc2ljcyBvZiBcYGdncGxvdDIoKScgYnkgdmlzdWFsaXppbmcgYSBzYW1wbGUgZGF0YSBzZXQKCkxlYXJuaW5nIE91dGNvbWVzOiBVbmRlcnN0YW5kIHRoZSBwdXJwb3NlIGFuZCBlZmZlY3RpdmUgdXNlIG9mIHRoZSBmb2xsb3dpbmcgdG9vbHMg4oCTbGluZSBjaGFydCwgaGlzdG9ncmFtLCBib3ggcGxvdCwgc2NhdHRlciBwbG90LCBidWJibGUgY2hhcnQsIGFuZCBidWxsZXQgZ3JhcGguCgojIENsZWFyIHRoZSB3b3Jrc3BhY2UKCkxldCdzIHN0YXJ0IHdpdGggY2xlYW5pbmcgdGhlIHdvcmtzcGFjZSBhbmQgbG9hZGluZyB0aGUgcmVxdWlyZWQgcGFja2FnZXMuIFRvZGF5LCB3ZSB3aWxsIHVzZSBhIG5ldyBwYWNrYWdlLCBgZ2dwbG90MigpYCwgd2hpY2ggaXMgYSBwb3dlcmZ1bCBSIGdyYXBoaWMgcGFja2FnZS4gSSBoaWdobHkgcmVjb21tZW5kIHRoaXMgc2l0ZSAoYW5kIGJvb2spIGZvciBtb3JlIGV4YW1wbGVzOiA8aHR0cDovL3d3dy5jb29rYm9vay1yLmNvbS9HcmFwaHMvPgoKYGBge3J9CnJtKGxpc3QgPSBscygpKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90MikKYGBgCgojIFVuZGVyc3RhbmRpbmcgdGhlIGRhdGFzZXQKCkluIHRoaXMgZXhlcmNpc2UsIHdlIHdpbGwgdXNlIHRoZSBjcmltZSBzdGF0aXN0aWNzIGluIGxhcmdlIFUuUy4gY2l0aWVzIGZvciAyMDA5LTIwMTQuIFRoaXMgZGF0YXNldCBpcyBvYnRhaW5lZCBmcm9tIHRoZSBVbmlmb3JtIENyaW1lIFJlcG9ydHMgKFVDUikgcHVibGlzaGVkIGJ5IHRoZSBGQkkgKDxodHRwczovL3Vjci5mYmkuZ292L2NyaW1lLWluLXRoZS11LnMvMjAxNC9jcmltZS1pbi10aGUtdS5zLi0yMDE0PikuIFRoaXMgZmlsZSBpbmNsdWRlcyB0aGUgbnVtYmVyIG9mIGNyaW1lIG9jY3VycmVuY2VzIHBlciBwb3B1bGF0aW9uIChjcmltZSByYXRlcykgYW5kIHRoZSBudW1iZXIgb2YgcG9saWNlIG9mZmljZXJzIGtpbGxlZCBvciBhc3NhdWx0ZWQgaW4gdGhlIGxpbmUgb2YgZHV0eS4KCjEpICBEb3dubG9hZCAqQ3JpbWVzIDIwMDktMjAxNC54bHN4KiBmcm9tIENhbnZhcyAqTW9kdWxlcyBcPiBXZWVrIDIqLgoyKSAgT3BlbiB0aGUgZmlsZSBpbiBFeGNlbCwgYW5kIGJyb3dzZSB0aGUgZGF0YS4KMykgIFRha2UgYSBsb29rIGF0IERhdGEgRGljdGlvbmFyeSB0YWIsIGFuZCB1bmRlcnN0YW5kIHdoYXQgZWFjaCBjcmltZSBkYXRhIGF0dHJpYnV0ZSBpcyBmb3IuCgpgYGB7cn0KY3JpbWVzIDwtIHJlYWRfZXhjZWwoIkNyaW1lcyAyMDA5LTIwMTQueGxzeCIpCgpjcmltZXMKYGBgCgpgYGB7cn0KZ2xpbXBzZShjcmltZXMpCmBgYAoKIyBEYXRhIFByZXBhcmF0aW9uCgpUaGUgbmFtZXMgb2YgdmFyaWFibGVzIGNvbnRhaW4gc3BhY2VzLCB3aGljaCBtYWtlIGl0IGRpZmZpY3VsdCB0byBtYW5hZ2UgaW4gUi4gTGV0J3MgcmVuYW1lIHZhcmlhYmxlcy4KCmBgYHtyfQojIENoYW5nZSB0aGUgdmFyaWFibGUgbmFtZXMKY29sbmFtZXMoY3JpbWVzKTwtYygiY2l0eSIsInN0YXRlIiwicmVnaW9uIiwiZGF0ZSIsInBvcHVsYXRpb24iLCJtdXJkZXJfcmF0ZSIsInZpb2xlbnRfY3JpbWVfcmF0ZSIsInZpb2xlbnRfY3JpbWVfcmF0ZV9wciIsInByb3BlcnR5X2NyaW1lX3JhdGUiLCJvZmZpY2VyX2Fzc2F1bHRfcmF0ZSIpCmdsaW1wc2UoY3JpbWVzKQpgYGAKCkFsc28sIGNoYW5nZSB0aGUgdmFyaWFibGUgdHlwZSBvZiBgZGF0ZWAgYXMgYSBkYXRlIHZhcmlhYmxlIGFuZCBjcmVhdGUgYHllYXJgIGZvciBmdXJ0aGVyIGFuYWx5c2lzLgoKYGBge3J9CiMgY3JlYXRlIHllYXIgdmFyaWFibGUKY3JpbWVzJGRhdGU8LWFzLkRhdGUoY3JpbWVzJGRhdGUsIiVtLSVkLSVZIikKY3JpbWVzCmNyaW1lcyR5ZWFyPC1mb3JtYXQoY3JpbWVzJGRhdGUsIiVZIikKZ2xpbXBzZShjcmltZXMpCmBgYAoKIyBTY2F0dGVyIHBsb3QKCkxldCdzIHN0YXJ0IGJ5IGV4YW1pbmluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZpb2xlbnQgY3JpbWUgcmF0ZSBhbmQgdGhlIHByb3BlcnR5IGNyaW1lIHJhdGUgaW4gdGhlIG1ham9yIGNpdGllcy4gWW91IGNhbiB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBvZiB0d28gbnVtZXJpYyB2YXJpYWJsZXMgYnkgcGxvdHRpbmcgYSBzY2F0dGVyIHBsb3Qgd2hlcmUgeC0gYW5kIHktYXhpcyByZXByZXNlbnRzIGVhY2ggbnVtZXJpYyB2YXJpYWJsZS4KCiMjIEJhc2UgUiBwbG90IGZ1bmN0aW9uCgpVc2luZyBiYXNlIFIgcGxvdCBmdW5jdGlvbjoKCmBgYHtyfQpwbG90KGNyaW1lcyR2aW9sZW50X2NyaW1lX3JhdGUsIGNyaW1lcyRwcm9wZXJ0eV9jcmltZV9yYXRlKQpgYGAKCkhvd2V2ZXIsIHRoZSBjb21iaW5hdGlvbiBvZiBgdGlkeXZlcnNlYCBhbmQgYGdncGxvdDJgIGNhbiBoZWxwIHlvdSBjcmVhdGUgYSBuaWNlci1sb29raW5nIGNoYXJ0IGluIGEgbW9yZSBpbnRyaW5zaWMgd2F5IHdpdGggbW9yZSBmbGV4aWJpbGl0eS4KCiMjIGdncGxvdDogSW50cm8KCmBnZ3Bsb3QoKWAgdGFrZXMgYSBkYXRhc2V0IGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYW5kIHlvdSBzcGVjaWZ5IGFlc3RoZXRpY3MgKGUuZy4gYXhlcywgY29sb3IsIHR5cGUsIGV0Yykgd2l0aCB0aGUgcGFyYW1ldGVycyBpbiBgYWVzKClgLgoKSW4gYGdncGxvdCgpYCwgeW91IHNwZWNpZnkgdGhlIGRhdGFzZXQgYW5kIGFlc3RoZXRpY3MsIGFuZCBcYGdlb21fcG9pbnQoKSBpbmRpY2F0ZXMgeW91J2QgbGlrZSB0byBjcmVhdGUgYSBzY2F0dGVyIHBsb3QuCgpgYGB7cn0KZ2dwbG90KGNyaW1lcywgYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpKwogIGdlb21fcG9pbnQoKQpgYGAKCldlIGNhbiBjcmVhdGUgdGhlIHNhbWUgcGxvdCB3aXRoIGEgcGlwZSBvcGVyYXRvcjoKCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpKwogIGdlb21fcG9pbnQoKQpgYGAKCiMjIENoYW5nZSBjb2xvcnMsIGRhdGEgcG9pbnQgc2l6ZXMsIGV0YwoKSWYgeW91IHdhbnQgdG8gYXBwbHkgdGhlIGRpZmZlcmVudCBjb2xvciwgc2hhcGUsIGV0YywgZm9yICphbGwqIHBvaW50cywgeW91IGNhbiBkbyBpdCBieSBjaGFuZ2luZyB0aGUgcGFyYW1ldGVyIGluIFxgZ2VvbV9wb2ludCgpJy4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpK2dlb21fcG9pbnQoc2l6ZT01KQoKY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKStnZW9tX3BvaW50KHNpemU9NSwgYWxwaGE9MC4yKSAjYWxwaGEgZm9yIHRyYW5zcGFyZW5jeTogZm9yIGRlbnNlbHkgcG9wdWxhdGVkIGRhdGEgcG9pbnRzCgpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpK2dlb21fcG9pbnQoY29sPSJibHVlIikKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD12aW9sZW50X2NyaW1lX3JhdGUseT1wcm9wZXJ0eV9jcmltZV9yYXRlKSkrZ2VvbV9wb2ludChzaGFwZT00KQoKY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKStnZW9tX3BvaW50KGNvbD0yLHNoYXBlPTIsc2l6ZSA9MykKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD12aW9sZW50X2NyaW1lX3JhdGUseT1wcm9wZXJ0eV9jcmltZV9yYXRlKSkrCiAgZ2VvbV9wb2ludChjb2w9IiM4NjIyOUEiLHNoYXBlPTIsc2l6ZSA9MykrCiAgbGFicyh0aXRsZT0iVmlvbGVudCB2cy4gUHJvcGVydHkgQ3JpbWUgUmF0ZSIsIHg9IlZpb2xlbnQgQ3JpbWUgUmF0ZSIsIHk9IlByb3BlcnR5IENyaW1lIFJhdGUiKQoKYGBgCgojIyBEaWZmZXJlbnQgY29sb3JzLCBzaXplcywgZXRjLiBieSBncm91cHMKCklmIHlvdSB3YW50IHRvIHVzZSBkaWZmZXJlbnQgY29sb3JzIGJ5IGRpZmZlcmVudCBncm91cHMsIHlvdSBjYW4gZG8gaXQgZWFzaWx5IGJ5IHNldHRpbmcgaXQgaW4gYGFlcygpYCEgWW91IGNhbiBjaGFuZ2UgdGhlIGFlc3RoZXRpY3MgdG8gZGVsaXZlciBtb3JlIGluZm9ybWF0aW9uIG9uIGEgY2hhcnQuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUsIHNpemU9b2ZmaWNlcl9hc3NhdWx0X3JhdGUpKStnZW9tX3BvaW50KCkKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD12aW9sZW50X2NyaW1lX3JhdGUseT1wcm9wZXJ0eV9jcmltZV9yYXRlLCBjb2w9cmVnaW9uKSkrZ2VvbV9wb2ludCgpCmBgYAoKWW91IGNhbiBkbyBpdCBpbiBjb21iaW5hdGlvbiEKCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSxzaXplPW9mZmljZXJfYXNzYXVsdF9yYXRlLGNvbD1yZWdpb24pKSsKICBnZW9tX3BvaW50KHNoYXBlPTEpCmBgYAoKTm90ZSB0aGF0IE9mZmljZXIgQXNzYXVsdCBSYXRlIGlzIHRoZSBudW1iZXIgb2YgcG9saWNlIG9mZmljZXJzIGtpbGxlZCBvciBhc3NhdWx0ZWQgaW4gdGhlIGxpbmUgb2YgZHV0eS4gVGhpcyBidWJibGUgY2hhcnQgbm93IHNob3dzIHRoYXQgcG9saWNlIG9mZmljZXJzIGFyZSBpbiBtb3JlIGRhbmdlciAoYXMgc2hvd24gaW4gYmlnZ2VyIGNpcmNsZXMpIGluIGNpdGllcyB3aXRoIGhpZ2hlciBjcmltZSByYXRlcy4KCiMjIEZhY2V0CgpZb3UgY2FuIGFsc28gZWFzaWx5IGNyZWF0ZSBzZXBhcmF0ZSBjaGFydHMgYnkgc3ViZ3JvdXBzIChpLmUuIHJlZ2lvbnMgaW4gdGhpcyBjYXNlKSB1c2luZyBgZmFjZXRfd3JhcCgpYCwgd2hpY2ggY3JlYXRlcyBjaGFydHMsIHdoaWNoIHNoYXJlIHRoZSBzYW1lIGF4ZXMsIGFuZCBkaXNwbGF5cyB0aGVtIGluIGEgcGFuZWwuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh5PXByb3BlcnR5X2NyaW1lX3JhdGUseD12aW9sZW50X2NyaW1lX3JhdGUsc2l6ZT1vZmZpY2VyX2Fzc2F1bHRfcmF0ZSxjb2xvdXI9cmVnaW9uKSkrCiAgZ2VvbV9wb2ludChzaGFwZT0xKSsKICBmYWNldF93cmFwKH5yZWdpb24pCmBgYAoKIyMgQWRkIGEgc3RhdGlzdGljcyBsYXllcgoKV2UgY2FuIGFsc28gYWRkIHNvbWUgc3RhdGlzdGljYWwgYW5hbHlzaXMgcmVzdWx0cyB0byB0aGUgY2hhcnRzLgoKTE9FU1MsIHdoaWNoIGlzIGEgZGVmYXVsdCBzbW9vdGhpbmcgbWV0aG9kIG9mIGBnZW9tX3Ntb290aCgpYCwgaXMgYSBub24tcGFyYW1ldHJpYyBmb3JtIG9mIHJlZ3Jlc3Npb24gdGhhdCB1c2VzIGEgd2VpZ2h0ZWQsIHNsaWRpbmctd2luZG93LCBhdmVyYWdlIHRvIGNhbGN1bGF0ZSBhIGxpbmUgb2YgYmVzdCBmaXQuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX3BvaW50KHNoYXBlPTEpKwogIGdlb21fc21vb3RoKG1ldGhvZD1sb2VzcykKYGBgCgpBIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGNhbiBiZSBhZGRlZCBpbnRvIGEgc2NhdHRlciBwbG90IGJ5IGFkZGluZyBzcGVjaWZ5aW5nIHRoZSBzbW9vdGhpbmcgbWV0aG9kIGFzICJsbSIuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX3BvaW50KHNoYXBlPTEpKwogIGdlb21fc21vb3RoKG1ldGhvZD1sbSkKYGBgCgpVc2luZyBgZmFjZXRfd3JhcCgpYCwgeW91IGNhbiBjb21wYXJlIHRoZSB0cmVuZCBieSBkaWZmZXJlbnQgcmVnaW9ucyBpbiB0aGUgVW5pdGVkIFN0YXRlcy5gZnVsbHJhbmdlPVRSVUVgIGV4dGVuZHMgdGhlIHNwYW4gb2YgdGhlIGxpbmVhciBtb2RlbCB0byB0aGUgZnVsbCByYW5nZS4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSwgY29sPXJlZ2lvbikpKwogIGdlb21fcG9pbnQoc2hhcGU9MSkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLGZ1bGxyYW5nZT1UUlVFKSsKICBmYWNldF93cmFwKH5yZWdpb24pCmBgYAoKIyBCYXIgY2hhcnRzCgpBIGJhciBjaGFydCBpcyBhIHNpbXBsZSB3YXkgdG8gZGVwaWN0IHRoZSBmcmVxdWVuY2llcyBvZiB0aGUgdmFsdWVzIG9mIGEgKmNhdGVnb3JpY2FsKiBhdHRyaWJ1dGUuCgpIb3cgbWFueSBjaXRpZXMgYXJlIGNvbnRhaW5lZCBpbiB0aGlzIGRhdGFzZXQgYnkgcmVnaW9uPyBJbiBmYWN0LCB0aGUgZGF0YXNldCBpcyBhIHBhbmVsIGRhdGFzZXQgKGkuZS4gcmVwZWF0ZWQgb2JzZXJ2YXRpb25zIG92ZXIgdGltZSBmb3IgdGhlIHNhbWUgZW50aXRpZXMpIGF0IGEgY2l0eS15ZWFyIGxldmVsLCB3aGVyZSBlYWNoIGNpdHkgYXBwZWFycyBvbmNlIHBlciB5ZWFyLiBTbywgd2UgY2FuIGNvdW50IHRoZSBudW1iZXIgb2YgY2l0aWVzLCBpZiB3ZSBzZXQgYHllYXJgIHRvIGEgc3BlY2lmaWMgeWVhciAoZS5nLiBgeWVhcj0yMDAwYCksIGFuZCBjb3VudCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucy4KCkxldCdzIGZpbHRlciBkYXRhIHdpdGggYHllYXI9PTIwMDBgIGFuZCB0aGVuIGNhbGwgYGdncGxvdCgpYCB3aXRoIGBnZW9tX2JhcigpYCB0byBjcmVhdGUgYSBiYXIgY2hhcnQuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHllYXI9PTIwMDApJT4lCiAgZ2dwbG90KGFlcyh4PXJlZ2lvbikpKwogIGdlb21fYmFyKCkKYGBgCgojIEhpc3RvZ3JhbQoKQSBoaXN0b2dyYW0gc2hvd3MgdGhlIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gZm9yIGEgbnVtZXJpY2FsIGF0dHJpYnV0ZS4KClRoZSByYW5nZSBvZiBhIG51bWVyaWNhbCBhdHRyaWJ1dGUgaXMgZGlzY3JldGl6ZWQgaW50byBhIGZpeGVkIG51bWJlciBvZiBpbnRlcnZhbHMgKOKAnGJpbnPigJ0pLCB1c3VhbGx5IG9mIGVxdWFsIGxlbmd0aC4gRm9yIGVhY2ggaW50ZXJ2YWwsIHRoZSAoYWJzb2x1dGUpIGZyZXF1ZW5jeSBvZiB2YWx1ZXMgZmFsbGluZyBpbnRvIGVhY2ggaW50ZXJ2YWwgaXMgaW5kaWNhdGVkIGJ5IHRoZSBoZWlnaHQgb2YgYSBiYXIuCgpMZXQncyBleGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHByb3BlcnR5IGNyaW1lIHJhdGUuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX2hpc3RvZ3JhbSgpCmBgYAoKIyMgQ2hhbmdlIGJpbiB3aWR0aCwgZmlsbCwgY29sb3IuLgoKVHJ5IGNoYW5naW5nIHRoZSB2YWx1ZSBvZiBgYmlud2lkdGhgLiBZb3Ugd2lsbCBzZWUgdGhlIHNoYXBlIG9mIHRoZSBoaXN0b2dyYW0gY2hhbmdlcy4gQWxzbywgYXMgd2UgZGlkIHdpdGggYSBzY2F0dGVycGxvdCwgeW91IGNhbiBjaGFuZ2UgdGhlIGNvbG9yIG9mIHRoZSBoaXN0b2dyYW0uCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xMDAwLCBjb2w9ImJsYWNrIixmaWxsPSJyZWQiKQpgYGAKCiMjIE92ZXJsYXBwaW5nIGhpc3RvZ3JhbXMKCldlIGNhbiBlYXNpbHkgY3JlYXRlIGhpc3RvZ3JhbXMgZm9yIGRpZmZlcmVudCByZWdpb25zIHVzaW5nIGBmYWNldF93cmFwKClgLgoKYGBge3J9CmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD1wcm9wZXJ0eV9jcmltZV9yYXRlLCBmaWxsPXJlZ2lvbikpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMCkrCiAgZmFjZXRfd3JhcCh+cmVnaW9uKQpgYGAKCkJ1dCB5b3UgY2FuIGFsc28gZGlzcGxheSB0aGVzZSBoaXN0b2dyYW1zIGluIG9uZSBjaGFydCB3aXRoIHZhcmlvdXMgb3B0aW9ucy4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9cHJvcGVydHlfY3JpbWVfcmF0ZSxmaWxsPXJlZ2lvbikpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMCkKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD1wcm9wZXJ0eV9jcmltZV9yYXRlLGZpbGw9cmVnaW9uKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MTAwLGFscGhhPTAuMywgcG9zaXRpb249ImlkZW50aXR5IikKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD1wcm9wZXJ0eV9jcmltZV9yYXRlLGZpbGw9cmVnaW9uKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MTAwLHBvc2l0aW9uPSJzdGFjayIpCgpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9cHJvcGVydHlfY3JpbWVfcmF0ZSxmaWxsPXJlZ2lvbikpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMDAscG9zaXRpb249ImRvZGdlIikKYGBgCgpJbnN0ZWFkIG9mIGEgaGlzdG9ncmFtLCB5b3UgY2FuIGNyZWF0ZSBhIGRlbnNpdHkgZnVuY3Rpb24gaW4gYSBzaW1pbGFyIG1hbm5lci4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9cHJvcGVydHlfY3JpbWVfcmF0ZSwgZmlsbD1yZWdpb24pKSsKICBnZW9tX2RlbnNpdHkoYWxwaGE9MC41KQpgYGAKCiMgQm94IHBsb3QKCkEgYm94cGxvdCBpcyBhIHZlcnkgY29tcGFjdCB3YXkgdG8gdmlzdWFsaXplIGFuZCBzdW1tYXJpemUgdGhlIGtleSBzdGF0aXN0aWNzIG9mIGEgbnVtZXJpYyBhdHRyaWJ1dGUuCgpMZXQncyBleGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHByb3BlcnR5IGNyaW1lIHJhdGUgKHdoaWNoIHdpbGwgYmUgZGlzcGxheWVkIGluIHktYXhpcykgYnkgY2l0aWVzICh3aGljaCB3aWxsIGJlIHgtYXhpcykuIEJlY2F1c2Ugd2UgaGF2ZSB0b28gbWFueSBjaXRpZXMgaW4gb3VyIGRhdGFzZXRzLCBsZXQncyBmb2N1cyBvbiB0aGUgY2l0aWVzIGluIEZsb3JpZGEuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iRkwiKSU+JQogIGdncGxvdChhZXMoeD1jaXR5LHk9cHJvcGVydHlfY3JpbWVfcmF0ZSxmaWxsPWNpdHkpKSsKICBnZW9tX2JveHBsb3QoKQpgYGAKClRoZSB1cHBlciB3aGlza2VyIGV4dGVuZHMgZnJvbSB0aGUgaGluZ2UgdG8gdGhlIGxhcmdlc3QgdmFsdWUgbm8gZnVydGhlciB0aGFuIDEuNSBcKiBJUVIgZnJvbSB0aGUgaGluZ2UgKHdoZXJlIElRUiBpcyB0aGUgaW50ZXItcXVhcnRpbGUgcmFuZ2UsIG9yIGRpc3RhbmNlIGJldHdlZW4gdGhlIGZpcnN0IGFuZCB0aGlyZCBxdWFydGlsZXMpLiBUaGUgbG93ZXIgd2hpc2tlciBleHRlbmRzIGZyb20gdGhlIGhpbmdlIHRvIHRoZSBzbWFsbGVzdCB2YWx1ZSBhdCBtb3N0IDEuNSBcKiBJUVIgb2YgdGhlIGhpbmdlLiBEYXRhIGJleW9uZCB0aGUgZW5kIG9mIHRoZSB3aGlza2VycyBhcmUgY2FsbGVkICJvdXRseWluZyIgcG9pbnRzIGFuZCBhcmUgcGxvdHRlZCBpbmRpdmlkdWFsbHkuCgojIFRpbWUgU2VyaWVzIHdpdGggTGluZSBHcmFwaAoKTGV0J3MgZXhhbWluZSB0aGUgdHJlbmQgb2YgdGhlIHZpb2xlbnQgY3JpbWUgcmF0ZSBvZiB0aGUgY2l0aWVzIGluIE5ldyBZb3JrIHN0YXRlLiBMZXQncyBmaXJzdCBleGFtaW5lIHRoZSBkYXRhLgoKYGBge3J9CmNyaW1lcyU+JQogIGZpbHRlcihzdGF0ZT09Ik5ZIiklPiUKICBkaXN0aW5jdChjaXR5KQoKY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iTlkiKQpgYGAKCkZvciBsaW5lIGdyYXBocywgdGhlIGRhdGEgcG9pbnRzIG11c3QgYmUgZ3JvdXBlZCBzbyB0aGF0IGl0IGtub3dzIHdoaWNoIHBvaW50cyB0byBjb25uZWN0LiBJZiB5b3Ugd2FudCB0byBjb25uZWN0IGFsbCBwb2ludHMsIHNldCBgZ3JvdXA9MWAuIEJlY2F1c2Ugd2Ugd2FudCB0byBjb25uZWN0IHRoZSBwb2ludHMgYnkgY2l0aWVzLCB3ZSB3aWxsIHNldCBgZ3JvdXA9Y2l0eWAuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iTlkiKSU+JQogICBnZ3Bsb3QoYWVzKHg9eWVhcix5PXZpb2xlbnRfY3JpbWVfcmF0ZSxncm91cD1jaXR5KSkrZ2VvbV9saW5lKCkKYGBgCgpCdXQgd2UgbG9zdCB0aGUgaW5mb3JtYXRpb24gYWJvdXQgd2hpY2ggbGluZSBpcyBmb3Igd2hpY2ggY2l0eS4gTGV0J3MgdXNlIGRpZmZlcmVudCB0eXBlcyBvciBjb2xvcnMgb2YgbGluZXMsIHNvIHRoYXQgd2UgY2FuIGRpc3Rpbmd1aXNoIHRoZW0uCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iTlkiKSU+JQogICBnZ3Bsb3QoYWVzKHg9eWVhcix5PXZpb2xlbnRfY3JpbWVfcmF0ZSwgZ3JvdXA9Y2l0eSxjb2w9Y2l0eSkpK2dlb21fbGluZSgpCgpjcmltZXMlPiUKICBmaWx0ZXIoc3RhdGU9PSJOWSIpJT4lCiAgIGdncGxvdChhZXMoeD15ZWFyLHk9dmlvbGVudF9jcmltZV9yYXRlLCBncm91cD1jaXR5LGxpbmV0eXBlPWNpdHkpKStnZW9tX2xpbmUoKQpgYGAKCiMgQXNzaWdubWVudCAyCgpCeSBtb2RpZnlpbmcgdGhlIGNvZGUgYmVsb3csIGNyZWF0ZSBib3ggcGxvdHMgdGhhdCBzaG93IHRoZSByYW5nZSBvZiB0aGUgdmlvbGVudCBjcmltZSByYXRlIGZvciBlYWNoIHN0YXRlIGluIHRoZSBTb3V0aCByZWdpb24sIHdoZXJlIGVhY2ggYm94IHJlcHJlc2VudHMgYSBzdGF0ZS4gRllJLCBzaXggc3RhdGVzIGFyZSBjYXRlZ29yaXplZCBhcyBTb3V0aCBpbiB0aGUgZGF0YXNldC4gQWZ0ZXIgY3JlYXRpbmcgdGhlIGNoYXJ0LCBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuCgpgYGB7cn0KY3JpbWVzICU+JQogIGZpbHRlcihyZWdpb24gPT0gIlNvdXRoIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc3RhdGUsIHkgPSB2aW9sZW50X2NyaW1lX3JhdGUsIGZpbGw9c3RhdGUpKSArCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgpRMS4gV2hpY2ggc3RhdGUgaGFzIHRoZSBjaXR5IHRoYXQgaGFzIHRoZSBsb3dlc3QgdmlvbGVudCBjcmltZSByYXRlIGluIHRoZSBTb3V0aCByZWdpb24/CgpLWTogS2VudHVja3kKClEyLiBXaGljaCBzdGF0ZSBoYXMgdGhlIGhpZ2hlc3QgbWVkaWFuIHZhbHVlIG9mIHRoZSB2aW9sZW50IGNyaW1lIHJhdGU/CgpUZW5uZXNzZWUgKFROKQoKUTMuIEJ5IG1vZGlmeWluZyB0aGUgY29kZSBiZWxvdywgY3JlYXRlIHNjYXR0ZXJwbG90cyB0aGF0IHNob3cgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBvZmZpY2VyIGFzc2F1bHQgcmF0ZSAoeC1heGlzKSBhbmQgdGhlIG11cmRlciByYXRlICh5LWF4aXMpIGJ5IHRoZSBzdGF0ZXMgaW4gdGhlIE5vcnRoZWFzdCByZWdpb24uIEl0IHdpbGwgcHJvZHVjZSBmb3VyIHNjYXR0ZXIgcGxvdHMgd2l0aCByZWdyZXNzaW9uIGxpbmVzLCBvbmUgZm9yIGVhY2ggc3RhdGUuCgpXaGljaCBzdGF0ZSBzaG93cyB0aGUgc3Ryb25nZXN0ICpuZWdhdGl2ZSogY29ycmVsYXRpb24gKGkuZS4gdGhlIHN0ZWVwZXIsIGRvd253YXJkIHNsb3BlIG9mIHJlZ3Jlc3Npb24gbGluZXMpPwoKTkogOiBOZXcgSmVyc2V5CgpgYGB7cn0KY3JpbWVzICU+JQogIGZpbHRlcihyZWdpb24gPT0gIk5vcnRoZWFzdCIpICU+JQogIGdncGxvdChhZXMoeCA9IG9mZmljZXJfYXNzYXVsdF9yYXRlLCB5ID0gbXVyZGVyX3JhdGUpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgZnVsbHJhbmdlID0gVFJVRSkgKwogIGZhY2V0X3dyYXAofiBzdGF0ZSkKYGBgCgpRNC5CeSBtb2RpZnlpbmcgdGhlIGNvZGUgYmVsb3csIGNyZWF0ZSBhIGhpc3RvZ3JhbSB0aGF0IHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgcHJvcGVydHkgY3JpbWUgcmF0ZSBpbiB5ZWFyIDIwMDIuIFNldCB0aGUgYmlud2lkdGg9MjAwMC4gV2hpY2ggb2YgdGhlIGJpbnMgY29udGFpbnMgdGhlIGxhcmdlc3QgbnVtYmVyIG9mIGNpdGllcz8KCmBgYHtyfQpjcmltZXMgJT4lCiAgZmlsdGVyKHllYXIgPT0gIjIwMDIiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwcm9wZXJ0eV9jcmltZV9yYXRlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMjAwMCwgY29sb3VyID0gImJsYWNrIiwgZmlsbCA9ICJ3aGl0ZSIpCmBgYAoKKDEpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDAgdG8gMjUwMC4KKDIpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDI1MDAgdG8gNTAwMC4KKDMpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDUwMDAgdG8gNzUwMC4KKDQpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDc1MDAgdG8gMTAwMDAuCig1KSBUaGUgYmluIHdob3NlIHgtYXhpcyB2YWx1ZXMgZ28gZnJvbSAxMDAwMC4gdG8gMTI1MDAKCkFuc3dlcjogVGhlIGJpbiB3aG9zZSB4LWF4aXMgdmFsdWVzIGdvIGZyb20gNTAwMCB0byA3NTAwLiBUaGlzIGJpbiBjb250YWlucyBtb3JlIHRoYW4gNDAgY2l0aWVzLCBtYWtpbmcgaXQgdGhlIG9uZSB3aXRoIHRoZSBsYXJnZXN0IG51bWJlciBvZiBjaXRpZXMgaW4gMjAwMi4KClE1LiBTaW1pbGFyIHRvIEFzc2lnbm1lbnQgMSwgZ2VuZXJhdGUgYSByZXBvcnQgZnJvbSAiQ3JlYXRpbmctQ2hhcnRzLVN0dWRlbnQuUm1kIi4gVGhpcyB0aW1lLCBwbGVhc2Uga25pdCBpdCBpbiBhIFdvcmQgZG9jdW1lbnQuIENoYW5nZSB0aGUgYXV0aG9yIG5hbWUgb24gdGhlIHRvcCBvZiB0aGlzIFIgbWFya2Rvd24gZmlsZSB0byB5b3VyIG5hbWUuIENvbXBpbGUgdGhpcyBSIG1hcmtkb3duIGZpbGUgaW50byBhIFdvcmQgZG9jdW1lbnQgYW5kIHN1Ym1pdCBpdCB0aHJvdWdoIHRoZSBjb3Vyc2UgQ2FudmFzLiBZb3VyIHJlcG9ydCBzaG91bGQgY29udGFpbiBhbGwgdGhlIGNvZGVzIGFuZCB0aGUgcmVzdWx0cyBvZiBpbi1jbGFzcyBleGVyY2lzZXMgYXMgd2VsbCBhcyB0aGUgY29kZXMgZm9yIHRoZSBhc3NpZ25tZW50IHF1ZXN0aW9ucy4KClE2LiBDcmVhdGUgYSBkYXNoYm9hcmQgd2l0aCBUYWJsZWF1IGJ5IGZvbGxvd2luZyB0aGUgaW5zdHJ1Y3Rpb24gaW4gIkNyZWF0aW5nLUNoYXJ0cy1UYWJsZWF1LmRvYyIuIEFmdGVyIGNyZWF0aW5nIGEgZGFzaGJvYXJkLCBleHBvcnQgeW91ciBUYWJsZWF1IGRhc2hib2FyZCB2aWV3IGFzIFBvd2VyUG9pbnQuIENsaWNrIOKAnEZpbGVcPkV4cG9ydCBBcyBQb3dlcnBvaW504oCdLCBhbmQgaW5jbHVkZSDigJxUaGlzIFZpZXfigJ0uIEl0IHdpbGwgY3JlYXRlIGEgUFBUIGZpbGUgdGhhdCBpbmNsdWRlcyBhIHNuYXBzaG90IG9mIHRoZSBkYXNoYm9hcmQuIFN1Ym1pdCB0aGlzIHBwdCBmaWxlIHRocm91Z2ggQ2FudmFzIGFzIHlvdXIgYW5zd2VyIGZvciBRdWVzdGlvbiA2Lgo=